#include <tsin/library/TouhouSoloViewport.hpp>
#include <tsin/library/TouhouSpellBasic.hpp>

#include <tsin/ondisk/GameEvent.hpp>
#include <tsin/ondisk/BulletEventFiller.hpp>

#include <tsin/library/BulletGenerator.hpp>
#include <tsin/library/BulletCirclePlacer.hpp>
#include <tsin/library/BulletCircleDirector.hpp>
#include <tsin/library/BulletLineRouter.hpp>
#include <tsin/library/BulletFadingDresser.hpp>
#include <tsin/library/BuiltinBullets.hpp>

#include <tsin/library/BulletDieOutEvent.hpp>
#include <tsin/library/BulletReflectEvent.hpp>

#include <tsin/runtime/GameRuntime.hpp>
#include <tsin/runtime/BulletRuntime.hpp>

#include "common.hpp"

using namespace tsin;

#define _USE_MATH_DEFINES
#include <cmath>

class MODULE_DLLEXPORT MyBulletFiller : public BulletEventFiller {
public:
        MyBulletFiller() {}

        virtual void reset() {}

        virtual void fill(BulletRuntime *bullet) {
                BulletDieOutEvent *dieOut = new BulletDieOutEvent();
                dieOut->init(60);
                bullet->addBulletEvent(dieOut);
                //BulletReflectEvent *reflect = new BulletReflectEvent();
                //reflect->init(REFLECT_LEFT | REFLECT_RIGHT | REFLECT_TOP | REFLECT_BOTTOM, 1);
                //bullet->addBulletEvent(reflect);
        }
};

class MODULE_DLLEXPORT MyGameEvent1 : public GameEvent {
private:
        BulletGenerator generator;

        BulletCirclePlacer placer;
        BulletCircleDirector director;
        BulletLineRouter router;
        BulletFadingDresser dresser;
        MyBulletFiller filler;

        int tick, round;
        float r, angle, v;
public:
        MyGameEvent1() : tick(11970), round(0), r(-20.0f), angle(M_PI/41), v(0.12f) {}

        void init(GameRuntime &game) {
                dresser.init(TOUHOU_SMALL_BULLET_SERIES, CIRCLE, DARK_BLUE);

                generator.setPlacer(&placer);
                generator.setDirector(&director);
                generator.setRouter(&router);
                generator.setDresser(&dresser);
                generator.setEventFiller(&filler);
        }

        bool trigger(GameRuntime &game) {
                if (round < 12000 && ++tick >= 3) {
                        tick = 0;
                        return true;
                }
                return false;
        }

        GameEvent *handle(GameRuntime &game) {
                static int nr = 32;
                static float pre = 1;
                placer.init(0.0f, 0.0f, r, nr, true, angle);
                director.init(nr, true, angle + pre*M_PI/2 - pre * 10*M_PI/20);
                router.init(v);
                generator.generate(&game, game.game->getViewport(0), nr);

                round ++;
                if (r < 25.0f) {
                        r += 1.0f;
                        v -= 0.01f;
                } else {
                        r = -20.0f;
                        pre = -pre;
                        if (nr < 15) nr ++;
                        tick = -1200;
                        v = 0.12f;
                }
                angle += pre * (M_PI / 30 + 0.002f);
                return this;
        }
} myGameEvent1;

class MODULE_DLLEXPORT MySpell : public TouhouSpellBasic {
public:
        MySpell() : TouhouSpellBasic() {
                name = "Hello";
                front.init(library::thSoloMiddleViewport, r640x480);
                frontImagePath = RES_PREFIX "front/front128.png";
        }

        int getEvents(GameEvent **events) {
                events[0] = &myGameEvent1;
                return 1;
        }
} mySpell;

extern "C" MODULE_DLLEXPORT Game *games[] = {
        &mySpell,
        0
};
